﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using ALiteTeam.PackageTracer.Service.Identifier;

namespace ALiteTeam.PackageTracer.Service
{
    public class SfIdentifier : Identify
    {
        private Bitmap _Original;
        private Bitmap[] _Pics;
        private int _GrayValue;
        private LevenshteinDistance _Distance;

        public static Dictionary<string, char> Chars = new Dictionary<string, char>()
        {
            // TO 0
            {"00000011110000000001111110000000111001110000011100001110000111000011100001110000111000011100001110000111000011100001110000111000011100001110000011100111000000011111100000000011110000",'0'}, 
            // TO 1
            {"00000001110000000011111100000000111111000000000001110000000000011100000000000111000000000001110000000000011100000000000111000000000001110000000000011100000000111111110000001111111110",'1'}, 
            // TO 2
            {"01111110000000111111110000001000010110000000000011100000000000111000000000001100000000000110000000000011000000000011100000000001110000000000111000000000001111111110000011111111100000", '2'}, 
            // TO 3
            {"00000011111000000001111111000000010000111000000000001110000000000111100000001111100000000011111000000000000111000000000000111000000000001110000001000111100000011111110000000011111000", '3'}, 
            // TO 4
            {"00000000011100000000001111000000000111110000000011011100000000110111000000011001110000001100011100000110000111000001111111111100011111111111000000000111000000000001110000000000011100", '4'},
            // TO 5
            {"00011111111000000111111110000001100000000000011000000000000111110000000001111111000000000001111000000000001110000000000011100000000000111000000100011110000001101111000000001111000000",'5'}, 
            // TO 6
            {"00011111000000001111111000000111100010000001110000000000111000000000001110111100000011111111100000111100111100001110000111000011100001110000011100111100000011111110000000011111000000",'6'}, 
            // TO 7
            {"00011111111100000111111111000000000000110000000000011000000000001100000000000011000000000001100000000000111000000000001100000000000111000000000001100000000000111000000000001110000000", '7'}, 
            // TO 8
            {"00000111100000000011111100000001110011100000011100011000000111101110000000111111000000001111110000000111011110000011100011110000111000011100001111000111000001101111100000001111110000", '8'}, 
            // TO 9
            {"00011111000000001111111000000111100111000001110000111000011100001110000111100111100000111111111000000111101110000000000011100000000001110000001000111100000011111110000000011111000000", '9'}, 


            // TO A
            {"00000011110000000000111100000000001111000000000110111000000001101110000000011011100000001100011100000011000111000000011111110000011111111110000110000011100001100000011000110000000111", 'A'},
            // TO B
            {"00011111110000000111111110000001110010100000011100111000000111001100000001111110000000011111110000000111001110000001110001110000011100011100000111000111000001111111110000011111111000", 'B'},
            // TO C
            {"00001111110000001111011110000111100000100001110000000000111000000000001110000000000011100000000000111000000000001110000000000001110000000000011110000010000011111111100000001111110000", 'C'},
            // TO D
            {"00111111110000001111111110000011100001110000111000011100001110000011100011100000111000111000001110001110000011100011100000111000111000011100001110001011000011111111100000111111110000", 'D'},
            // TO E
            {"01111111110000011111111100000111000000000001110000000000011100000000000111111110000001111111100000011100000000000111000000000001110000000000011100000000000111111011000001111111110000", 'E'}, 
            // TO F
            {"01111111100000011111111000000111000000000001110000000000011100000000000111111100000001111110000000011100000000000111000000000001110000000000011100000000000111000000000001110000000000", 'F'},
            // TO G
            {"00000011111100000011111111100001111000001000011100000000001110000000000011100000000000111000000000001110000011100011100000111000011100001110000111100011100000111111111000000011111110", 'G'},
            // TO H
            {"00011100000111000111000001110001110000011100011100000111000111000001110001111111111100011111111111000111000001110001110000011100011100000111000111000001110001110000011100011100000111", 'H'}, 
            // TO I
            {"00111000000000001110000000000011100000000000111000000000001110000000000011100000000000111000000000001110000000000011100000000000111000000000001110000000000011100000000000111000000000", 'I'},
            // TO J
            {"1100000001110100000000111010000000011100000000001110000000000111000000000011100000000001110000000000111000000000011100000000001110000000000111000000000011100000000001110000000000111000000111111000000011111000", 'J'},
            // TO K
            {"11100000011000111000001100001110000110000011100011000000111001100000001110110000000011111100000000111011100000001110011100000011100011100000111000011100001110000011100011100000011100", 'K'}, 
            // TO L
            {"11100000000000111000000000001110000000000011100000000000111000000000001110000000000011100000000000111000000000001110000000000011100000000000111000000000001111111110000011111111100000", 'L'},
            // TO M
            {"00111100000111001111000001110011111000111100111110001111001111100011110011011101101100110111011011001101110110110011001101101100110011110011001100111100110011001111001100110000000011", 'M'},
            // TO N
            {"00011000000011000111000000110001111000001100011111000011000111110000110001101110001100011001110011000110001110010001100001111100011000011111000110000011110001100000011100011000000011", 'N'},
            // TO O
            {"00001111110000000111111110000011110011110000111000011100011100000011100111000000111001110000001110011100000011100111000000111000111000011100001111001111000001111111000000001111110000", 'O'},
            // TO P
            {"00001111111100000011111111100000111000111000001110001110000011100111100000111111110000001111111000000011100000000000111000000000001110000000000011100000000000111000000000001110000000", 'P'},
            // TO Q
            {"00001111110000000111111110000011110011110000111000011100011100000011100111000000111001110000001110011100000011100111000000111000110000011100001111001111000001111111100000001111110000000000001111100000000000111100000000000011", 'Q'}, 
            // TO R
            {"00011111010000000111111111000001110001110000011100011100000111000111000001110011100000011111110000000111111100000001110011100000011100011100000111000111000001110000111000011100000111", 'R'},
            // TO S
            {"00001111000000000111111000000011100010000000111000000000001110000000000001111000000000001111100000000000111000000000000111000000000001110000001000011100000011111110000000011111000000", 'S'},
            // TO T
            {"11111111111000111111111110000000111000000000001110000000000011100000000000111000000000001110000000000011100000000000111000000000001110000000000011100000000000111000000000001110000000", 'T'},
            // TO U
            {"00111000001100001110000011000011100000110000111000001100001110000011000011100000110000111000001100001110000011000011100000110000111000001100001111000111000001111111100000001111110000", 'U'},
            // TO V
            {"11100000001100011100000110000111000001100001110000011000001110001100000011100011000000111000110000000111011000000001110010000000011101100000000011110000000000111100000000001111000000", 'V'}, 
            // TO W
            {"00111000111100001110001111000011100011110000011100110100000111001011000001110110111000011101101110000111011011100001110110111000001101000111000010110001110000111100011100001111000111", 'W'},
            // TO X
            {"01110000000110001110000011000001110001100000011100110000000011101100000000011110000000000111100000000001111000000000110111000000001100111000000110001110000011000001110001100000001110", 'X'},
            // TO Y
            {"11100000011000001100001100000111000011000000111001100000001110011000000001111100000000001110000000000011100000000000111000000000001110000000000011100000000000111000000000001110000000", 'Y'},
            // TO Z
            {"00111111111000001111111111000000000001110000000000111000000000011100000000001110000000000011000000000001110000000000111000000000011100000000001110000000000011111111100000111111111100", 'Z'}

        };

        private SfIdentifier()
        {
            _Distance = new LevenshteinDistance();
        }

        private static SfIdentifier _Instance;
        public static SfIdentifier Instance
        {
            get
            {
                if (_Instance == null)
                {
                    _Instance = new SfIdentifier();
                }

                return _Instance;
            }
        }

        /// <summary>
        /// 识别单个数字
        /// </summary>
        /// <param name="bmpSingle"></param>
        /// <returns></returns>
        public char GetSingleCode(Bitmap bmpSingle)
        {
            char result = '?';

            //_GrayValue = 113;
            string feature = CodeIdentitierUtil.GetSingleBmpFeature(bmpSingle, _GrayValue);

            decimal currentMaxSimilarity = 0;
            decimal eachTimeValue;

            List<KeyValuePair<int, decimal>> similarities = new List<KeyValuePair<int, decimal>>();

            foreach(string str in Chars.Keys)
            {
                eachTimeValue = _Distance.LevenshteinDistancePercent(feature, str);
                if (eachTimeValue > currentMaxSimilarity)
                {
                    result = Chars[str];
                    currentMaxSimilarity = eachTimeValue;
                }
            }

            if (currentMaxSimilarity < 0.90m)
            {
                result = '_';
            }
            return result;
        }

        /// <summary>
        /// 识别一个验证码图片，返回验证码文字
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public string Identity(Bitmap bitmap)
        {
            string result = string.Empty;
            _Original = new Bitmap(bitmap);

            Bitmap newBitMap;
            newBitMap = CodeIdentitierUtil.GrayByPixels(_Original, false);
            _GrayValue = CodeIdentitierUtil.GetDgGrayValue(_Original);
            newBitMap = CodeIdentitierUtil.GetPicValidByValue(newBitMap, _GrayValue, 4);            
            _Pics = CodeIdentitierUtil.GetSplitPics(newBitMap, 4, 1);

            foreach (var pic in _Pics)
            {
                result += GetSingleCode(pic).ToString();
            }

            return result;
        }

        public string Identity(Stream stream)
        {
            string result;
            
            Bitmap bmp = new Bitmap(stream);            
            result = Identity(bmp);

            return result;
        }
    }
}
